package com.infindo.frame.util;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
 
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONStringer;
import org.json.JSONTokener;

import android.util.Log;

import com.infindo.frame.data.mo.MoliscMessage;
import com.infindo.frame.data.mo.ServiceMessage;
 

public class JSONUtil {

 
	private final static String MO_PACKAGES="com.tiantian.app.data.mo.";
	
	public static String messageToJSONStringer(MoliscMessage message) throws Exception {
	    return wrapObject(message).toString();
	    
	}
	
    public static MoliscMessage strToMoliscMessage(String msg,String cmsListParameters) {
        MoliscMessage mm = null;
        try {
            JSONObject obj =  new JSONObject(msg);
            String clazz = obj.getString("clazz");
            mm = (MoliscMessage)convertToBean(obj,clazz,true);
            
            //only for list and map types
            mm.toObject(obj,cmsListParameters);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return mm;
    }
 	
	
	public static String serviceMessageToJSONStringer(ServiceMessage sm) throws Exception {
		
		JSONStringer jsonStr = new JSONStringer()
		.object()
		.key("clazz").value(sm.getClazz())
		.key("uid").value(sm.getUid())
		.key("platform").value(sm.getPlatform())
		.key("versionId").value(sm.getVersionId())
		.key("appId").value(sm.getAppId())
		.key("parameters").value(new JSONArray(sm.getParameters()))
		.key("serMethod").value(sm.getSerMethod())
		.endObject();
		return jsonStr.toString();
	}
	
	@SuppressWarnings("unchecked")
	public static JSONObject wrapObject(Object obj) throws Exception {
	    if (obj == null)
	        return null;
	    
        JSONObject jo = new JSONObject();

        final String get = "get";
        final String set = "set";
        final String is = "is";
        int begin = 0;

        Class objClass = obj.getClass();

        Method[] objMethods = objClass.getMethods();

        for (int i = 0; i < objMethods.length; i++) {
            Method method = objMethods[i];

            if (method.getName().startsWith(get)
                    || method.getName().startsWith(is)) {
                if (method.getName().startsWith(get)) {
                    begin = get.length();
                } else {
                    begin = is.length();
                }
                try {
                    // Method invMethod=objClass.getMethod(setMethodName,new Class[]{method.getReturnType()});
                    String srcMethodName = method.getName().substring(begin);
                    String firstLetter = srcMethodName.substring(0, 1);
                    firstLetter = firstLetter.toLowerCase();
                    srcMethodName = firstLetter + srcMethodName.substring(1);
                    
                    if(srcMethodName.equalsIgnoreCase("class")){
                    	continue;
                    }
                    if(srcMethodName.equalsIgnoreCase("clazz")){
                    	
                    }
                    Class c = method.getReturnType();
                    boolean hashMapType = false;
                    boolean listType = false;
                    if (c.equals(Map.class)) {
                        hashMapType = true;
                    } else if (c.equals(List.class)) {
                        listType = true;
                    }
                    Object result = null;
                    if (hashMapType) {
                        Map<String, Object> mapValues = (Map<String, Object>)method.invoke(obj, new Object[] {});
                        JSONObject joMap = new JSONObject();
                        Iterator<String> it = mapValues.keySet().iterator();
                        String key = null;
                        while (it.hasNext()) {
                            key = (String)it.next();
                            Object objMap = mapValues.get(key);
                            joMap.put(key, wrapObject(objMap));
                        }
                        //jo.put(srcMethodName, joMap);
                        result = joMap;
                    } else if (listType) {
                        List<Object> listValues = (List<Object>)method.invoke(obj, new Object[] {}); 
                        //JSONObject joList = new JSONObject();
                        JSONArray jsonArray =new JSONArray();
                        
                        for (Object objL: listValues) {
                            jsonArray.put(wrapObject(objL));
                        }
                        //joList.put(srcMethodName, jsonArray);
                        result = jsonArray;
                    } else {

                        result = method.invoke(obj, new Object[] {});
                    }
                    jo.put(srcMethodName, result);
//                    Log.e("jo","jo.put ====   srcMehodName:"+srcMethodName+"   reulst:"+result);
                } catch (Exception e) {
                    Log.e(JSONUtil.class.getName(), "wrapObject error=" + e.getMessage());
                    continue;
                }
            }
        }

        return jo;
    }
	@SuppressWarnings("unchecked")
	public static Object convertToBean(JSONObject jsonObj,String clazz,boolean copyNull){	 
		
		Class jsonClazz=null;
		try {
			jsonClazz = Class.forName(MO_PACKAGES + clazz);
		} catch (ClassNotFoundException e1) {
			e1.printStackTrace();
			Log.e(JSONUtil.class.getName(), e1.getMessage());
		}
		
		Object beanObject=null;
		try {
			beanObject = jsonClazz.newInstance();
		} catch (IllegalAccessException e1) {
			Log.e(JSONUtil.class.getName(), e1.getMessage());
		} catch (InstantiationException e1) {
			Log.e(JSONUtil.class.getName(), e1.getMessage());
		} 
		 
		 final String get="get";
		 final String set="set";
		 final String is="is";
		 int begin = 0;
		 
		 Class desClass=beanObject.getClass();
		 
		 Method[] descMethods=desClass.getMethods();
		 
		 for(int i=0;i<descMethods.length;i++){
			 Method method=descMethods[i];
			 @SuppressWarnings("unused")
			String methodName = method.getName();
//			Log.d(JSONUtil.class.getName(), "methodName="+methodName);
			 
			 if(method.getName().startsWith(get)||method.getName().startsWith(is)){
                 
                 if (method.getName().equalsIgnoreCase("getClass")) {
                     continue;
                 }
			     
				 if(method.getName().startsWith(get)){
					 begin = get.length();
				 }else{
					 begin = is.length();
				 }
				 String setMethodName=set+method.getName().substring(begin);
				 
				 
				 try{
					 Method invMethod=desClass.getMethod(setMethodName,new Class[]{method.getReturnType()});
//					 Log.d(JSONUtil.class.getName(), "returnType="+method.getReturnType());
					 String srcMethodName = method.getName().substring(begin);

                     
					 String firstLetter = srcMethodName.substring(0, 1);
					 firstLetter = firstLetter.toLowerCase();
//					 Log.d(JSONUtil.class.getName(), "firstLetter="+firstLetter);
					 srcMethodName = firstLetter+srcMethodName.substring(1);
//					 Log.d(JSONUtil.class.getName(), "srcMethodName="+srcMethodName);


					 
					 Class c=method.getReturnType();
					 
					 boolean listArrayType=false;
					 boolean hashMapType = false;
					 if (c.equals(List.class)) {
						 listArrayType=true;
					 } else if (c.equals(Map.class)){
					     hashMapType = true;
					 }
//					 Log.v(JSONUtil.class.getName(), c.getName()+"  convertToBean prop: " + setMethodName + " listArrayType="+listArrayType);
					 
					 List listValues=null;
					 Object result =null;
					 Map<String, Object> mapValues = null;
					 if (listArrayType){
						 listValues=new ArrayList();
						 String jsonStr = jsonObj.getString(srcMethodName);
						 JSONTokener jt = new JSONTokener(jsonStr);
						 JSONArray jsonArray =new JSONArray(jt);
						 for (int idata=0;idata<jsonArray.length();idata++){
							 JSONObject jooo = jsonArray.getJSONObject(idata);
//							 Log.d(JSONUtil.class.getName(),"jooo:"+jooo.toString());
//							 Log.d(JSONUtil.class.getName(), "returnType="+method.getReturnType());
							 ParameterizedType pt= (ParameterizedType)method.getGenericReturnType(); 
							 Class type = (Class)pt.getActualTypeArguments()[0]; 
//							 Log.d(JSONUtil.class.getName(), "  ===============  return Type Name="+type.getSimpleName());
                             String className = type.getSimpleName();					 
							 Object myObj = convertToBean(jooo, className, true);
							 listValues.add(myObj);
						 }
					 }else if (hashMapType) {
					    mapValues = new HashMap<String, Object>();
					    //String jsonStr = jsonObj.getString(srcMethodName);
					    //JSONObject jso = new JSONObject(jsonStr);
					    JSONObject jso = jsonObj.getJSONObject(srcMethodName);
					    if (jso.length() > 0) {
    					    JSONArray jsonArray = jso.names();
    					    for (int idata=0;idata<jsonArray.length();idata++){
    					        String mapKey = jsonArray.getString(idata);
    					        JSONObject value = jso.getJSONObject(mapKey);
    					        String className=value.getString("clazz");
    					        Object myObj = convertToBean(value, className, true);
    					        mapValues.put(mapKey, myObj);
    					        
    					    }
					    }
					 } else {
						 try{
						     if (c.equals(Long.class)) {
						         result = jsonObj.getLong(srcMethodName);
						     } else if (c.equals(Integer.class)) {
						    	  result = jsonObj.getInt(srcMethodName);
						     } else if(c.equals(String.class)){
						    	 result = jsonObj.getString(srcMethodName);
						     } else if (c.equals(java.util.Date.class)){
						    	 result = jsonObj.get(srcMethodName);
						    	 Long second = (Long) result;
						    	 result = new java.util.Date(second);
						     } else if(c.equals(Float.class)){
						    	 result = jsonObj.get(srcMethodName);
						    	 Double floatObj = (Double)result;
						    	 result = new java.lang.Float(floatObj);
						     } else if(c.equals(Double.class)){
						    	 result = jsonObj.getDouble(srcMethodName);
						     } else {
//						         result = jsonObj.get(srcMethodName);
								 JSONObject value = jsonObj.getJSONObject(srcMethodName);
								 String className=value.getString("clazz");
								 result = convertToBean(value, className, true);
						     }
				    	 }catch(JSONException je){ }
						 if(result==null||result.equals("null"))
							 continue;
					 }
					 
					 if(!copyNull&&(result==null||listValues==null)){
						 continue;
					 }

					 
					 if (listArrayType) {
						 invMethod.invoke( beanObject  ,new Object[]{ listValues}); 
					 } else if (hashMapType) {
					     //HashMap map = (HashMap)result;
					     invMethod.invoke( beanObject  ,new Object[]{mapValues});
					 } else {
						 if(result !=null && !result.equals("null"))
							 invMethod.invoke( beanObject  ,new Object[]{result});
					 }
					     
				 
				 }catch(Exception e){
					 Log.e(JSONUtil.class.getName(), "convertToBean prop: " + setMethodName + " error="+e.getMessage());
					 continue;
				 }
			 }
		 }
		 return beanObject;
	}    
	
	/*private static Object convertToLiteObject(JSONObject jsonObj,String clazz,boolean copyNull){	 
		
		Class jsonClazz=null;
		try {
			jsonClazz = Class.forName(clazz);
		} catch (ClassNotFoundException e1) {
			e1.printStackTrace();
			Log.d(JSONUtil.class.getName(), e1.getMessage());
		}
		
		Object beanObject=null;
		try {
			beanObject = jsonClazz.newInstance();
		} catch (IllegalAccessException e1) {
			Log.e(JSONUtil.class.getName(), e1.getMessage());
		} catch (InstantiationException e1) {
			Log.e(JSONUtil.class.getName(), e1.getMessage());
		} 
		 
		 final String get="get";
		 final String set="set";
		 final String is="is";
		 int begin = 0;
		 
		 Class desClass=beanObject.getClass();
		 
		 Method[] descMethods=desClass.getMethods();
		 
		 for(int i=0;i<descMethods.length;i++){
			 Method method=descMethods[i];
			 String methodName = method.getName();
			// Log.d(JSONUtil.class.getName(), "methodName="+methodName);
			 
			 if(method.getName().startsWith(get)||method.getName().startsWith(is)){
				 if(method.getName().startsWith(get)){
					 begin = get.length();
				 }else{
					 begin = is.length();
				 }
				 String setMethodName=set+method.getName().substring(begin);
				 
				 
				 try{
					 Method invMethod=desClass.getMethod(setMethodName,new Class[]{method.getReturnType()});
					// Log.d(JSONUtil.class.getName(), "returnType="+method.getReturnType());
					 String srcMethodName = method.getName().substring(begin);
					 String firstLetter = srcMethodName.substring(0, 1);
					 firstLetter = firstLetter.toLowerCase();
					// Log.d(JSONUtil.class.getName(), "firstLetter="+firstLetter);
					 srcMethodName = firstLetter+srcMethodName.substring(1);
					 //Log.d(JSONUtil.class.getName(), "srcMethodName="+srcMethodName);
					 
					 Object result =jsonObj.get(srcMethodName);
					  
					 if(!copyNull&&result==null){
						 continue;
					 }
					 invMethod.invoke( beanObject  ,new Object[]{result});
				 }catch(Exception e){
					 Log.e(JSONUtil.class.getName(), "convertToLiteObject() : error="+e.getMessage());
					 continue;
				 }
			 }
		 }
		 return beanObject;
	}    */
}
